package beanstao.util.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;

import beanstao.util.exception.technical.util.reflect.ReflectException;

/**
 * 反射工具类，提供各类反射相关的方法
 * 
 * @author beanstao@google.com 
 */
/**
 * @author beanstao@google.com 
 */
public class ReflectionUtils
{
	private final static ClassLoader CLASS_LOADER = ReflectionUtils.class.getClassLoader();

	/**
	 * 根据类名进行实例化
	 * 
	 * @param className
	 *            待实例化的类
	 * @return 返回实例化的对象
	 */
	public static Object instanceFromClassName(String className)
	{
		Class<?> clazz = getClass(className);
		return instance(clazz);
	}

	/**
	 * 根据类名进行实例化，并且验证待实例化的类是parentClass的子类
	 * 
	 * @param className
	 *            待实例化的类
	 * @param parentClass
	 *            目标类型
	 * @return 返回实例化的对象，
	 */
	public static Object instanceFromClassName(String className, Class<?> parentClass)
	{
		Class<?> clazz = getClass(className);
		if (clazz.isAssignableFrom(parentClass))
		{
			throw new ReflectException(clazz + "不是" + parentClass + "的子类。");
		}
		return instance(clazz);
	}

	/**
	 * 根据类的全路径名获得Class对象
	 * 
	 * @param className
	 *            类的全路径名，例如：com.leepweb.Test
	 */
	public static Class<?> getClass(String className)
	{
		try
		{
			return CLASS_LOADER.loadClass(className);
		}
		catch (ClassNotFoundException e)
		{
			throw new ReflectException("无法得到加载" + className, e);
		}
	}

	/**
	 * 实例化Class对象
	 * 
	 * @param clazz
	 *            Class对象
	 */
	public static Object instance(Class<?> clazz)
	{
		try
		{
			return clazz.newInstance();
		}
		catch (InstantiationException e)
		{
			throw new ReflectException("实例化" + clazz + "时发生异常", e);
		}
		catch (IllegalAccessException e)
		{
			throw new ReflectException("实例化" + clazz + "时发生异常", e);
		}
	}

	/**
	 * 实例化Class对象
	 * 
	 * @param clazz
	 * @param parameterTypes
	 * @param initargs
	 * @return
	 */
	public static Object instance(Class<?> clazz, Class<?>[] parameterTypes, Object[] initargs)
	{
		if (parameterTypes.length != initargs.length)
		{
			throw new ReflectException("实例化" + clazz + "所传递的参数与初始参数不一致，其中：parameterTypes的长度为" + parameterTypes.length + ", initargs的长度为" + initargs.length);
		}
		Constructor<?> c = getDeclaredConstructor(clazz, parameterTypes);
		try
		{
			return c.newInstance(initargs);
		}
		catch (IllegalArgumentException e)
		{
			throw new ReflectException("实例化" + c + "时发生异常，所传递initargs的长度为：" + initargs.length, e);
		}
		catch (InstantiationException e)
		{
			throw new ReflectException("实例化" + c + "时发生异常，所传递initargs的长度为：" + initargs.length, e);
		}
		catch (IllegalAccessException e)
		{
			throw new ReflectException("实例化" + c + "时发生异常，所传递initargs的长度为：" + initargs.length, e);
		}
		catch (InvocationTargetException e)
		{
			throw new ReflectException("实例化" + c + "时发生异常，所传递initargs的长度为：" + initargs.length, e);
		}
	}

	/**
	 * 得到类的指定构造函数
	 * 
	 * @param clazz
	 * @param parameterTypes
	 * @return
	 */
	public static Constructor<?> getDeclaredConstructor(Class<?> clazz, Class<?>... parameterTypes)
	{
		try
		{
			return clazz.getDeclaredConstructor(parameterTypes);
		}
		catch (SecurityException e)
		{
			throw new ReflectException("试图得到" + clazz + "的" + parameterTypes.length + "构造函数是报错。", e);
		}
		catch (NoSuchMethodException e)
		{
			throw new ReflectException("试图得到" + clazz + "的" + parameterTypes.length + "构造函数是报错。", e);
		}
	}

	/**
	 * 得到指定类中的方法，如果没有此方法，那么返回null，否则将返回正确Method对象
	 * 
	 * @param clazz
	 *            类
	 * @param name
	 *            方法名
	 * @param parameterTypes
	 *            参数列表
	 * @return
	 */
	public static Method getMethod(Class<?> clazz, String name, Class<?>... parameterTypes)
	{
		try
		{
			return clazz.getMethod(name, parameterTypes);
		}
		catch (SecurityException e)
		{
			throw new ReflectException("试图从" + clazz + "中得到" + name + "(" + parameterTypes.length + ")方法发生异常。", e);
		}
		catch (NoSuchMethodException e)
		{
			throw new ReflectException("试图从" + clazz + "中得到" + name + "(" + parameterTypes.length + ")方法发生异常。", e);
		}
	}

	/**
	 * 根据方法的前三位是“set”或“get”判断指定的对象中的方法类型，并返方法名为键，方法为值的集合
	 * 
	 * @param obj
	 * @param methodByMethod
	 * @return
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	public static HashMap<String, Method> getMethodMap(Object obj, String methodByMethod) throws IllegalAccessException, InvocationTargetException
	{
		HashMap<String, Method> methodes = new HashMap<String, Method>();
		Method[] methods = obj.getClass().getDeclaredMethods();
		for (Method method : methods)
		{
			String methodName = method.getName().substring(0, 3).toLowerCase();
			if (methodByMethod.equals(methodName))// 判断是否有指定的注解
			{
				methodes.put(method.getName().substring(3), method);
			}
		}
		return methodes;
	}

	/**
	 * 调用方法
	 * 
	 * @param method
	 * @param obj
	 * @param args
	 * @return
	 */
	public static Object invokeMethod(Method method, Object obj, Object... args)
	{
		try
		{
			return method.invoke(obj, args);
		}
		catch (IllegalArgumentException e)
		{
			throw new ReflectException("调用" + obj.toString() + "的" + method + "，参数为：" + args.length, e);
		}
		catch (IllegalAccessException e)
		{
			throw new ReflectException("调用" + obj.toString() + "的" + method + "，参数为：" + args.length, e);
		}
		catch (InvocationTargetException e)
		{
			throw new ReflectException("调用" + obj.toString() + "的" + method + "，参数为：" + args.length, e);
		}
	}
}
